#include <pthread.h>
#include <unistd.h>

#include <iostream>

using namespace std;

static int num = 0;
static pthread_rwlock_t rwlock;

void *read_handler(void *arg) {
  for (int i = 0; i < 5; ++i) {
    // 加读锁
    pthread_rwlock_rdlock(&rwlock);
    cout << "[READ " << (long long)arg << "] NUM = " << num << endl;
    fflush(stdout);
    pthread_rwlock_unlock(&rwlock);
    sleep(1);
  }
}

void *write_handler(void *arg) {
  for (int i = 0; i < 5; ++i) {
    // 加写锁
    pthread_rwlock_wrlock(&rwlock);
    num++;
    cout << "[WRITE " << (long long)arg << "] NUM CHANGE" << endl;
    fflush(stdout);
    pthread_rwlock_unlock(&rwlock);
    sleep(1);
  }
}

int main(int argc, char const *argv[]) {
  // 初始化读写锁
  pthread_rwlock_init(&rwlock, NULL);
  pthread_t pr1, pr2, pw1, pw2;
  pthread_create(&pr1, NULL, read_handler, (void *)1);
  pthread_create(&pr2, NULL, read_handler, (void *)2);
  pthread_create(&pw1, NULL, write_handler, (void *)1);
  pthread_create(&pw2, NULL, write_handler, (void *)2);
  pthread_join(pr1, NULL);
  pthread_join(pr2, NULL);
  pthread_join(pw1, NULL);
  pthread_join(pw2, NULL);
  pthread_rwlock_destroy(&rwlock);
  return 0;
}

/**
 * 如果有线程读数据，则允许其它线程执行读操作，但不允许写操作
 * 如果有线程写数据，则其它线程都不允许读、写操作
 * 如果某线程申请了读锁，其它线程可以再申请读锁，但不能申请写锁
 * 如果某线程申请了写锁，其它线程不能申请读锁，也不能申请写锁
 * 读写锁适合于对数据的读次数比写次数多得多的情况
 */
